/*
  Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/*
 * Test free functions found in utils.cc
 */

#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include <cstdlib>

#include "mysqlrouter/utils.h"
#include "utils.h"

using std::string;

using mysqlrouter::substitute_envvar;
using mysqlrouter::wrap_string;

using ::testing::StrEq;
using ::testing::ContainerEq;


class SubstituteEnvVarTest : public ::testing::Test {
protected:
  virtual void SetUp() {
      putenv(strdup((env_name + "=" + env_value).c_str()));
  }
  string env_name {"MYRTEST_ENVAR"};
  string env_value {"MySQLRouterTest"};
};

class WrapStringTest : public ::testing::Test {
protected:
  virtual void SetUp() {
  }
  string one_line {
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut ac tempor ligula. Curabitur imperdiet sem eget "
    "tincidunt viverra. Integer lacinia, velit vel aliquam finibus, dui turpis aliquet leo, pharetra finibus neque "
    "elit id sapien. Nunc hendrerit ut felis nec gravida. Proin a mi id ligula pharetra pulvinar ut in sapien. "
    "Cras lorem libero, mollis consectetur leo et, sollicitudin scelerisque mauris. Nunc semper dignissim libero, "
    "vitae ullamcorper arcu luctus eu."
  };
  string with_newlines {
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nUt ac tempor ligula. Curabitur imperdiet sem eget "
    "tincidunt viverra. Integer lacinia, velit\nvel aliquam finibus, dui turpis aliquet leo, pharetra finibus neque "
    "elit id sapien. Nunc hendrerit ut felis nec\ngravida. Proin a mi id ligula pharetra pulvinar ut in sapien. "
    "Cras lorem libero, mollis consectetur\nleo et, sollicitudin scelerisque mauris. Nunc semper dignissim libero, "
    "vitae ullamcorper arcu luctus\neu."
  };

  string short_line_less72 {
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
  };

  string custom_indents {
    "           Lorem ipsum dolor      sit amet,\n"
    "           consectetur adipiscing elit."
  };
};

class StringFormatTest : public ::testing::Test {
protected:
  virtual void SetUp() {
  }
};

/*! \brief Tests mysqlrouter::substitute_envvar()
 *
 */

TEST_F(SubstituteEnvVarTest, Simple)
{
string exp {env_value};
string test {"ENV{" + env_name + "}"};
substitute_envvar(test);
ASSERT_STREQ(exp.c_str(), test.c_str());
}

TEST_F(SubstituteEnvVarTest, SimpleMiddleOfString)
{
string exp {"ham/" + env_value + "/spam"};
string test {"ham/ENV{" + env_name + "}/spam"};
substitute_envvar(test);
ASSERT_STREQ(exp.c_str(), test.c_str());
}

TEST_F(SubstituteEnvVarTest, NoPlaceholder)
{
string test {"hamspam"};
ASSERT_THROW(substitute_envvar(test), mysqlrouter::envvar_no_placeholder);
try {
  substitute_envvar(test);
} catch (const mysqlrouter::envvar_no_placeholder &err) {
  EXPECT_STREQ("No environment variable placeholder found", err.what());
}
}

TEST_F(SubstituteEnvVarTest, UnclosedPlaceholder)
{
string env_test {"hamENV{" + env_name + "spam"};
ASSERT_THROW(substitute_envvar(env_test), mysqlrouter::envvar_bad_placeholder);
try {
  substitute_envvar(env_test);
} catch (const mysqlrouter::envvar_bad_placeholder &err) {
  EXPECT_STREQ("Environment placeholder not closed", err.what());
}
}

TEST_F(SubstituteEnvVarTest, EmptyVariableName)
{
string env_test {"hamENV{}spam"};
ASSERT_THROW(substitute_envvar(env_test), mysqlrouter::envvar_bad_placeholder);
try {
  substitute_envvar(env_test);
} catch (const mysqlrouter::envvar_bad_placeholder &err) {
  EXPECT_STREQ("No environment variable name found in placeholder", err.what());
}
}

TEST_F(SubstituteEnvVarTest, UnknownEnvironmentVariable)
{
string unknown_name {"UNKNOWN_VARIABLE_12343xyzYEKfk"};
string env_test {"hamENV{" + unknown_name + "}spam"};
ASSERT_THROW(substitute_envvar(env_test), mysqlrouter::envvar_not_available);
try {
  substitute_envvar(env_test);
} catch (const mysqlrouter::envvar_not_available &err) {
  EXPECT_STREQ(string({"Unknown environment variable " + unknown_name}).c_str(), err.what());
}
}

/*
 * Tests mysqlrouter::wrap_string()
 */

TEST_F(WrapStringTest, ShortLine)
{
  std::vector<string> lines = wrap_string(short_line_less72, 72, 0);

  std::vector<string> exp {short_line_less72};
  ASSERT_THAT(lines, ContainerEq(exp));
}

TEST_F(WrapStringTest, OneLine72width)
{
  std::vector<string> lines = wrap_string(one_line, 72, 0);

  std::vector<string> exp {
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut ac tempor",
    "ligula. Curabitur imperdiet sem eget tincidunt viverra. Integer lacinia,",
    "velit vel aliquam finibus, dui turpis aliquet leo, pharetra finibus",
    "neque elit id sapien. Nunc hendrerit ut felis nec gravida. Proin a mi id",
    "ligula pharetra pulvinar ut in sapien. Cras lorem libero, mollis",
    "consectetur leo et, sollicitudin scelerisque mauris. Nunc semper",
    "dignissim libero, vitae ullamcorper arcu luctus eu.",
  };

  ASSERT_THAT(lines, ContainerEq(exp));
}

TEST_F(WrapStringTest, OneLine72widthIndent4)
{
  std::vector<string> lines = wrap_string(one_line, 72, 4);

  std::vector<string> exp {
    "    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut ac",
    "    tempor ligula. Curabitur imperdiet sem eget tincidunt viverra.",
    "    Integer lacinia, velit vel aliquam finibus, dui turpis aliquet leo,",
    "    pharetra finibus neque elit id sapien. Nunc hendrerit ut felis nec",
    "    gravida. Proin a mi id ligula pharetra pulvinar ut in sapien. Cras",
    "    lorem libero, mollis consectetur leo et, sollicitudin scelerisque",
    "    mauris. Nunc semper dignissim libero, vitae ullamcorper arcu luctus",
    "    eu.",
  };

  ASSERT_THAT(lines, ContainerEq(exp));
}

TEST_F(WrapStringTest, RespectNewLine)
{
  std::vector<string> lines = wrap_string(with_newlines, 80, 0);

  std::vector<string> exp {
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
    "Ut ac tempor ligula. Curabitur imperdiet sem eget tincidunt viverra. Integer",
    "lacinia, velit",
    "vel aliquam finibus, dui turpis aliquet leo, pharetra finibus neque elit id",
    "sapien. Nunc hendrerit ut felis nec",
    "gravida. Proin a mi id ligula pharetra pulvinar ut in sapien. Cras lorem libero,",
    "mollis consectetur",
    "leo et, sollicitudin scelerisque mauris. Nunc semper dignissim libero, vitae",
    "ullamcorper arcu luctus",
    "eu.",
  };

  ASSERT_THAT(lines, ContainerEq(exp));
}

TEST_F(WrapStringTest, RespectNewLineIndent2)
{
  std::vector<string> lines = wrap_string(with_newlines, 60, 2);

  std::vector<string> exp {
      "  Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
      "  Ut ac tempor ligula. Curabitur imperdiet sem eget",
      "  tincidunt viverra. Integer lacinia, velit",
      "  vel aliquam finibus, dui turpis aliquet leo, pharetra",
      "  finibus neque elit id sapien. Nunc hendrerit ut felis nec",
      "  gravida. Proin a mi id ligula pharetra pulvinar ut in",
      "  sapien. Cras lorem libero, mollis consectetur",
      "  leo et, sollicitudin scelerisque mauris. Nunc semper",
      "  dignissim libero, vitae ullamcorper arcu luctus",
      "  eu.",
  };
  ASSERT_THAT(lines, ContainerEq(exp));
}

TEST_F(WrapStringTest, CustomeIndents)
{
  std::vector<string> lines = wrap_string(custom_indents, 72, 5);

  std::vector<string> exp {
      "                Lorem ipsum dolor      sit amet,",
      "                consectetur adipiscing elit.",
  };

  ASSERT_THAT(lines, ContainerEq(exp));
}

/*
 * Tests mysqlrouter::string_format()
 */
TEST_F(StringFormatTest, Simple)
{
  EXPECT_EQ(std::string("5 + 5 = 10"), mysqlrouter::string_format("%d + %d = %d", 5, 5, 10));
  EXPECT_EQ(std::string("Spam is 5"), mysqlrouter::string_format("%s is %d", "Spam", 5));
}
